package yawning.mew.character;

import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

import yawning.mew.equipment.DatabaseItemSource;
import yawning.mew.equipment.EquipSet;
import yawning.mew.equipment.Item;
import yawning.mew.equipment.ItemSource;
import yawning.mew.equipment.MemoryCacheItemSource;
import yawning.mew.equipment.WowheadItemSource;

public class ArmoryToonBuilder {
	private String mName;
	private String mRegion;
	private String mServer;
	private int mTalentGroup = 0;
	private Element mCharacterTab;

	@SuppressWarnings("serial")
	public class ArmoryCharacterBuildException extends Exception {
		ArmoryCharacterBuildException(Exception e) {
			super(e);
		}
		
		ArmoryCharacterBuildException(String s) {
			super(s);
		}
	}

	public ArmoryToonBuilder setName(String name) {
		mName = name;
		return this;
	}

	public ArmoryToonBuilder setRegion(String region) {
		mRegion = region;
		return this;
	}

	public ArmoryToonBuilder setServer(String server) {
		mServer = server;
		return this;
	}
	
	public ArmoryToonBuilder setTalentGroup(int group) {
		mTalentGroup = group;
		return this;
	}
	
	public EquipSet getEquipSet() {
		EquipSet mEquipSet = new EquipSet();
		@SuppressWarnings("unchecked") List<Element> itemList = mCharacterTab.getChild("items").getChildren("item");
		for (Element i : itemList) {
			Item item = new Item();
			item.mItem = ItemSource.getItem(Integer.parseInt(i.getAttributeValue("id")));
			
			int gem1 = Integer.parseInt(i.getAttributeValue("gem0Id"));
			if (gem1 > 0) item.mSocket1 = ItemSource.getItem(gem1);
			
			int gem2 = Integer.parseInt(i.getAttributeValue("gem1Id"));
			if (gem2 > 0) item.mSocket2 = ItemSource.getItem(gem2);

			int gem3 = Integer.parseInt(i.getAttributeValue("gem2Id"));
			if (gem3 > 0) item.mSocket3 = ItemSource.getItem(gem3);
			
			String permanentenchant = i.getAttributeValue("permanentEnchantItemId");
			if (permanentenchant != null) item.mEnchant = ItemSource.getItem(Integer.parseInt(permanentenchant));
			else {
				permanentenchant = i.getAttributeValue("permanentenchant");
				if (permanentenchant != null) {
					int enchant = Integer.parseInt(permanentenchant);
					if (enchant > 0) {
						String name = i.getAttributeValue("permanentEnchantSpellName");
						System.out.println("Unrecognized enchant " + enchant + " : " + name);
					}
				}
			}
			
			mEquipSet.addItem(item);
		}
		
		return mEquipSet;
	}

	public Toon build() throws ArmoryCharacterBuildException {
		try {
			URL url = new URL("http://" + mRegion + ".wowarmory.com/character-sheet.xml?r=" + mServer + "&cn=" + mName);
		    URLConnection urlc = url.openConnection();
		    urlc.setRequestProperty("User-Agent", "Firefox/3.5");
		    SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(urlc.getInputStream());
			Element charRoot = doc.getRootElement();
			Element characterInfo = charRoot.getChild("characterInfo");
			Element character = characterInfo.getChild("character");

			url = new URL("http://" + mRegion + ".wowarmory.com/character-talents.xml?r=" + mServer + "&cn=" + mName);
		    urlc = url.openConnection();
		    urlc.setRequestProperty("User-Agent", "Firefox/3.5");
		    builder = new SAXBuilder();
			doc = builder.build(urlc.getInputStream());
			Element talentRoot = doc.getRootElement();
			Element talents = talentRoot.getChild("characterInfo").getChild("talents");
		    
			Toon t = new Toon();
			t.mClass = Clazz.get(character.getAttributeValue("class"));
			t.mRace = Race.get(character.getAttributeValue("race"));
			t.level = Integer.parseInt(character.getAttributeValue("level"));
			
	    	// Parse through the talent groups
			@SuppressWarnings("unchecked") List<Element> talentGroups = talents.getChildren("talentGroup");
			for (Element i : talentGroups) {
				// TODO: Select from mTalentGroup instead of just grabbing active 
				if (i.getAttributeValue("active") != null) {
					// Copy the talent string
					String spec = i.getChild("talentSpec").getAttributeValue("value");
					t.talents = spec.getBytes();
					for (int j = 0; j < t.talents.length; j++) t.talents[j] -= '0';
					
					// Determine primary talent spec
					String primary = i.getAttributeValue("prim").toUpperCase();
					for (TalentTree ts : t.mClass.getTalentTrees()) if (ts.mName == primary) t.mTalentSpec = ts;
					
					// Obtain the glyphs
					@SuppressWarnings("unchecked") List<Element> glyphs = i.getChild("glyphs").getChildren("glyph");
					for (Element e : glyphs) {
						String glyphName = e.getAttributeValue("name");
				    	for (Glyph g : t.mClass.getGlyphs()) {
				    		if (glyphName == g.mName) {
					    		t.glyphs.add(g);
					    		break;
				    		}
				    	}
					}
				}
			}
			
			// Cache character tab for EquipSet parsing
			mCharacterTab = characterInfo.getChild("characterTab");
			
			Element baseStats = mCharacterTab.getChild("baseStats");
			t.strength = Integer.parseInt(baseStats.getChild("strength").getAttributeValue("effective"));
			t.agility = Integer.parseInt(baseStats.getChild("agility").getAttributeValue("effective"));
			t.stamina = Integer.parseInt(baseStats.getChild("stamina").getAttributeValue("effective"));
			t.intellect = Integer.parseInt(baseStats.getChild("intellect").getAttributeValue("effective"));
			t.spirit = Integer.parseInt(baseStats.getChild("spirit").getAttributeValue("effective"));
			t.armor = Integer.parseInt(baseStats.getChild("armor").getAttributeValue("effective"));
			
			Element melee = mCharacterTab.getChild("melee");
	    	t.attackPower = Integer.parseInt(melee.getChild("power").getAttributeValue("effective"));
	    	int strAP = Integer.parseInt(baseStats.getChild("strength").getAttributeValue("attack"));
	    	int agiAP = Integer.parseInt(baseStats.getChild("agility").getAttributeValue("attack"));
	    	if (strAP > 0) t.attackPower -= strAP;
	    	if (agiAP > 0) t.attackPower -= agiAP;
	    	
	    	t.hasteRating = Integer.parseInt(melee.getChild("mainHandSpeed").getAttributeValue("hasteRating"));
	    	t.critRating = Integer.parseInt(melee.getChild("critChance").getAttributeValue("rating"));
	    	t.hitRating = Integer.parseInt(melee.getChild("hitRating").getAttributeValue("value"));
	    	t.expertiseRating = Integer.parseInt(melee.getChild("expertise").getAttributeValue("rating"));
	    	t.masteryRating = 0; // TODO: Armory has to add this... soon... right?
	    	
	        t.weaponTop = Integer.parseInt(melee.getChild("mainHandDamage").getAttributeValue("max"));
	        t.weaponBottom = Integer.parseInt(melee.getChild("mainHandDamage").getAttributeValue("min"));
	        t.weaponSpeed = (int)(100 * Float.parseFloat(melee.getChild("mainHandDamage").getAttributeValue("speed")));
			
	        t.isArmorSpec = true; // TODO: Determine this for real
	        t.mMetaGem = null; // TODO: Determine this!
	        
			return t;
		} catch (Exception e) {
			throw new ArmoryCharacterBuildException(e);
		}
	}

	public static void main(String[] args) {
		ItemSource.pushBack(new MemoryCacheItemSource());
		ItemSource.pushBack(new DatabaseItemSource());
		ItemSource.pushBack(new WowheadItemSource());
		
		try {
			Toon ch = new ArmoryToonBuilder()
					.setName("Yawning")
					.setRegion("us")
					.setServer("Crushridge")
					.build();
			
			System.out.println(ch);
		}
		catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
